//
//  GameLayer.cpp
//  ___PROJECTNAME___
//
//  Created by ___FULLUSERNAME___ on ___DATE___.
//  Copyright ___ORGANIZATIONNAME___ ___YEAR___. All rights reserved.
//


#include "GameScene.h"

#include "MainMenuScene.h"
#include "Defines.h"
#include "Keys.h"
#include "Config.h"

#if (USE_DEBUG_HUD == 1)
#include "DebugHUD.h"
#endif

#include "Box2D.h"



using namespace cocos2d;

namespace ___game_namespace___ {

#define LEF_RIGHT_SHIF 50.f
#define UP_DOWN_SHIF 50.f

////////////////////////////////////////////////////////
//
/** GameScene
 * 
*/
////////////////////////////////////////////////////////

CCScene* GameScene::scene()
{
	GameScene *pRet = new GameScene();
	CCAssert(pRet != NULL, NULL);
	if (pRet->init())
	{
		pRet->autorelease();
        return pRet;
	}
	else
	{
		CC_SAFE_DELETE(pRet)
		return NULL;
	}
}

bool GameScene::init()
{
	if (!CCScene::init())
		return false;

	//Do something which not load resources

	return true;
}

GameScene::~GameScene()
{
	// Unload resources
}

void GameScene::onEnter()
{
    CCScene::onEnter();

	//Load resources
	//Attention! onEnter() and onExit() are used on CCDirector::pushScene()/popScene(). 
	//So load resources only if they are not loaded before (scene come from stack)!
	CCSize contentSize = this->getContentSize();
	contentSize.width -= LEF_RIGHT_SHIF*2.f;
	contentSize.height -= UP_DOWN_SHIF*2.f;
	CCNode* layer = GameLayer::node(contentSize);
	layer->setPosition(CCPoint(LEF_RIGHT_SHIF, UP_DOWN_SHIF));
	this->addChild(layer, 0);
}

void GameScene::onExit()
{
	//Stop activity

    CCScene::onExit();
}


////////////////////////////////////////////////////////
//
/** GameLayer
 *  Listining for touches and accelerometer
*/
////////////////////////////////////////////////////////

CCNode* GameLayer::node(const CCSize& contentSize)
{
	GameLayer *pRet = new GameLayer();
	CCAssert(pRet != NULL, NULL);
	if (pRet->init(contentSize))
	{
		pRet->autorelease();
        return pRet;
	}
	else
	{
		CC_SAFE_DELETE(pRet)
		return NULL;
	}
}

GameLayer::GameLayer()
: _world(NULL)
{

}

GameLayer::~GameLayer()
{
	delete _world;	_world = NULL;
}

bool GameLayer::init(const CCSize& contentSize)
{
	if (!CCLayer::init())
		return false;

	this->setContentSize(contentSize);

	// Start listining touches and accelerometer
	setIsTouchEnabled( true );
	setIsAccelerometerEnabled( true );


	//Start prepare phisics
    
	// Define the gravity vector.
	b2Vec2 gravity;
	gravity.Set(0.0f, -10.0f);
	
	// Do we want to let bodies sleep?
	bool doSleep = true;
    
	// Construct a _world object, which will hold and simulate the rigid bodies.
	_world = new b2World(gravity);
    _world->SetAllowSleeping(doSleep);    
	_world->SetContinuousPhysics(true);

	//Debug draw
#if (USE_DEBUG_HUD == 1)
	CCSize sz = contentSize; sz.width += LEF_RIGHT_SHIF; sz.height += UP_DOWN_SHIF*2.f;
	CCNode* debugHUD = DebugHUD::node(_world, sz, contentSize);
	debugHUD->setAnchorPoint(ccp(0.5f, 0.5f));
	debugHUD->setPosition(ccp(contentSize.width/2.f, contentSize.height/2.f));
	this->addChild(debugHUD, INT_MAX);
#endif

	// Create borders
	b2BodyDef groundBodyDef;
	groundBodyDef.position.Set(contentSize.width/2/PTM_RATIO, 
                               contentSize.height/2/PTM_RATIO); // bottom-left corner
	
	// Call the body factory which allocates memory for the ground body
	// from a pool and creates the ground box shape (also from a pool).
	// The body is also added to the _world.
	b2Body* groundBody = _world->CreateBody(&groundBodyDef);
	
	// Define the ground box shape.
	b2PolygonShape groundBox;		
	
    // bottom
    groundBox.SetAsBox(contentSize.width/2/PTM_RATIO, 0, b2Vec2(0, -contentSize.height/2/PTM_RATIO), 0);
 	groundBody->CreateFixture(&groundBox, 0);
	
    // top
    groundBox.SetAsBox(contentSize.width/2/PTM_RATIO, 0, b2Vec2(0, contentSize.height/2/PTM_RATIO), 0);
    groundBody->CreateFixture(&groundBox, 0);
    
    // left
    groundBox.SetAsBox(0, contentSize.height/2/PTM_RATIO, b2Vec2(-contentSize.width/2/PTM_RATIO, 0), 0);
    groundBody->CreateFixture(&groundBox, 0);
    
    // right
    groundBox.SetAsBox(0, contentSize.height/2/PTM_RATIO, b2Vec2(contentSize.width/2/PTM_RATIO, 0), 0);
    groundBody->CreateFixture(&groundBox, 0);
    

	//Stop prepare phisics

	
	// Add notification
	CCLabelTTF *label = CCLabelTTF::labelWithString("Tap screen", "Marker Felt", 32);
	label->setColor( ccc3(0,0,255) );
	label->setPosition( CCPointMake( contentSize.width/2, contentSize.height-50) );

	// Add menu
	CCMenu* menu = CCMenu::node();
    menu->setAnchorPoint(CCPointZero);
    menu->setPosition(CCPointZero);
    menu->setContentSize(contentSize);
    this->addChild(menu, 0);

	//Add Exit button
	CCMenuItemImage *menuItem = CCMenuItemImage::itemFromNormalImage(
			kTexBtnClose_normal,
			kTexBtnClose_selected,
			this,
			menu_selector(GameLayer::onClose) );
    menuItem->setAnchorPoint(ccp(1.f, 1.f));
    menuItem->setPosition(ccp(contentSize.width, contentSize.height));
    menu->addChild(menuItem, 0);

	//Add first figure
	addNewSpriteWithCoords( CCPointMake(contentSize.width/2, contentSize.height/2) );

	//Scedule update/tick
	schedule( schedule_selector(GameLayer::tick) );

	return true;
}

////////////////////////////////////////////////////////
// 

void GameLayer::addNewSpriteWithCoords(CCPoint p)
{	
	//We have a 64x64 sprite sheet with 4 different 32x32 images.  The following code is
	//just randomly picking one of the images
	int idx = (CCRANDOM_0_1() > .5 ? 0:1);
	int idy = (CCRANDOM_0_1() > .5 ? 0:1);
    
	CCSprite *sprite = CCSprite::spriteWithFile(kTexBlocks, CCRectMake(32.f * idx,32.f * idy,32.f,32.f));

//	CCNode *sprite = CCNode::node();
//	sprite->setAnchorPoint(CCPointZero);
//	sprite->setContentSize(CCSize(32.f, 32.f));
	
	sprite->setPosition( CCPointMake( p.x, p.y) );
	this->addChild(sprite, 0);

	
	// Define the dynamic body.
	//Set up a 1m squared box in the physics _world
	b2BodyDef bodyDef;
	bodyDef.type = b2_dynamicBody;
	bodyDef.position.Set(p.x/PTM_RATIO, p.y/PTM_RATIO);
	bodyDef.userData = sprite;
	b2Body *body = _world->CreateBody(&bodyDef);
	
	// Define another box shape for our dynamic body.
	b2PolygonShape dynamicBox;
	dynamicBox.SetAsBox(.5f, .5f);//These are mid points for our 1m box
	
	// Define the dynamic body fixture.
	b2FixtureDef fixtureDef;
	fixtureDef.shape = &dynamicBox;	
	fixtureDef.density = 1.0f;
	fixtureDef.friction = 0.3f;
	body->CreateFixture(&fixtureDef);
}


void GameLayer::tick(ccTime dt)
{
	//It is recommended that a fixed time step is used with Box2D for stability
	//of the simulation, however, we are using a variable time step here.
	//You need to make an informed choice, the following URL is useful
	//http://gafferongames.com/game-physics/fix-your-timestep/
	
	int velocityIterations = 8;
	int positionIterations = 1;
    
	// Instruct the _world to perform a single step of simulation. It is
	// generally best to keep the time step and iterations fixed.
	_world->Step(dt, velocityIterations, positionIterations);
	
	//Iterate over the bodies in the physics _world
	for (b2Body* b = _world->GetBodyList(); b; b = b->GetNext())
	{
		if (b->GetUserData() != NULL) {
			//Synchronize the AtlasSprites position and rotation with the corresponding body
			CCSprite* myActor = (CCSprite*)b->GetUserData();
			myActor->setPosition( CCPointMake( b->GetPosition().x * PTM_RATIO, b->GetPosition().y * PTM_RATIO) );
			myActor->setRotation( -1 * CC_RADIANS_TO_DEGREES(b->GetAngle()) );
		}	
	}
}

void GameLayer::ccTouchesEnded(CCSet* touches, CCEvent* event)
{
	//Add a new body/atlas sprite at the touched location
	CCSetIterator it;
	CCTouch* touch;
    
	for( it = touches->begin(); it != touches->end(); it++) 
	{
		touch = (CCTouch*)(*it);
        
		if(!touch)
			break;
        
		CCPoint location = touch->locationInView(touch->view());
		location = CCDirector::sharedDirector()->convertToGL(location);
		location = this->convertToNodeSpace(location);

		if (location.x > 0 && location.x < this->getContentSize().width &&
			location.y > 0 && location.y < this->getContentSize().height)
			addNewSpriteWithCoords( location );
	}
}

void GameLayer::didAccelerate(CCAcceleration* pAccelerationValue )
{
	CCLayer::didAccelerate(pAccelerationValue);

	b2Vec2 gravity((float)pAccelerationValue->x, (float)pAccelerationValue->y);

	float signX = (gravity.x < 0.f)? -1.f: 1.f;
	float signY = (gravity.y < 0.f)? -1.f: 1.f;

    gravity.x = signX * min(powf(fabs(gravity.x), 0.4f), 1.f);
	gravity.y = signY * min(powf(fabs(gravity.y), 0.4f), 1.f);

	gravity *= 10;

//	AppLog("ZmPhysicalLayer::didAccelerate %f %f", (float)pAccelerationValue->x, (float)pAccelerationValue->y);

	_world->SetGravity(b2Vec2(gravity.x, gravity.y));
}

void GameLayer::onClose(CCObject* caller)
{
	CCDirector::sharedDirector()->replaceScene(MainMenuScene::scene());
}


} // namespace ___game_namespace___
